package com.oceantrader.sale.commons.config.api;

import java.util.UUID;

import org.springframework.stereotype.Component;

import com.oceantrader.sale.constant.CacheKey;

import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.shareddata.AsyncMap;
import lombok.RequiredArgsConstructor;

/** Backend Api 鉴权 */
@Component
@RequiredArgsConstructor
public class BackendApiAuth {
    private final Vertx vertx;

    /**
     * 将用户标记登录
     * 
     * @param userId 用户ID
     * @return token
     */
    public Future<String> signin(Long userId) {
        Promise<String> result = Promise.promise();
        if (userId == null) {
            result.fail(new NullPointerException("userId can not be null"));
            return result.future();
        }
        String token = UUID.randomUUID().toString().replace("-", "");
        Future<AsyncMap<String, String>> user2tokenFuture = vertx.sharedData().<String, String>getAsyncMap(CacheKey.BACKEND_USER_TO_TOKEN);
        Future<AsyncMap<String, String>> token2userFuture = vertx.sharedData().<String, String>getAsyncMap(CacheKey.BACKEND_TOKEN_TO_USER);
        Future.all(user2tokenFuture, token2userFuture).onSuccess(asyncMapHandler -> {
            Future<Void> putFuture1 = asyncMapHandler.<AsyncMap<String, String>>resultAt(0).put(userId.toString(), token, 7 * 24 * 60 * 60 * 1000L);
            Future<Void> putFuture2 = asyncMapHandler.<AsyncMap<String, String>>resultAt(1).put(token, userId.toString(), 7 * 24 * 60 * 60 * 1000L);
            Future.all(putFuture1, putFuture2).onSuccess(v -> {
                result.complete(token);
            }).onFailure(e -> result.fail(e));
        }).onFailure(e -> result.fail(e));
        return result.future();
    }

    /**
     * 查询当前登录人
     * 
     * @param token 登录标识token
     * @return 用户ID
     */
    public Future<Long> check(String token) {
        Promise<Long> result = Promise.promise();
        if (token == null) {
            result.fail(new NullPointerException("token can not be null"));
            return result.future();
        }
        vertx.sharedData().<String, String>getAsyncMap(CacheKey.BACKEND_TOKEN_TO_USER).onSuccess(token2user -> {
            token2user.get(token).onSuccess(userIdString -> {
                Long userId = null;
                if (userIdString != null) {
                    userId = Long.parseLong(userIdString);
                }
                result.complete(userId);
            }).onFailure(e -> result.fail(e));
        }).onFailure(e -> result.fail(e));
        return result.future();
    }

    /**
     * 退出登录
     * 
     * @param token
     */
    public Future<Void> signout(String token) {
        Promise<Void> result = Promise.promise();
        if (token == null) {
            result.fail(new NullPointerException("token can not be null"));
            return result.future();
        }
        this.check(token).onSuccess(userId -> {
            if (userId == null) {
                result.complete();
                return;
            }
            Future<AsyncMap<String, String>> user2tokenFuture = vertx.sharedData().<String, String>getAsyncMap(CacheKey.BACKEND_USER_TO_TOKEN);
            Future<AsyncMap<String, String>> token2userFuture = vertx.sharedData().<String, String>getAsyncMap(CacheKey.BACKEND_TOKEN_TO_USER);
            Future.all(user2tokenFuture, token2userFuture).onSuccess(asyncMapHandler -> {
                Future<Void> removeFuture1 = asyncMapHandler.<AsyncMap<String, Void>>resultAt(0).remove(userId.toString());
                Future<Void> removeFuture2 = asyncMapHandler.<AsyncMap<String, Void>>resultAt(1).remove(token);
                Future.all(removeFuture1, removeFuture2).onSuccess(v -> {
                    result.complete();
                }).onFailure(e -> result.fail(e));
            }).onFailure(e -> result.fail(e));
        }).onFailure(e -> result.fail(e));
        return result.future();
    }
}
